package com.gitee.wsl.doc.prosemirror.state.command.block.list

import com.gitee.wsl.doc.prosemirror.model.fragment.Fragment
import com.gitee.wsl.doc.prosemirror.model.fragment.Slice
import com.gitee.wsl.doc.prosemirror.model.node.NodeType
import com.gitee.wsl.doc.prosemirror.state.Command
import com.gitee.wsl.doc.prosemirror.state.CommandDispatch
import com.gitee.wsl.doc.prosemirror.state.EditorState
import com.gitee.wsl.doc.prosemirror.transform.ext.step
import com.gitee.wsl.doc.prosemirror.transform.step.ReplaceAroundStep

class SinkListItem(val itemType: NodeType): Command {
    override fun exec(
        state: EditorState,
        dispatch: CommandDispatch?,
    ): Boolean {
        val selection = state.selection
        val from = selection._from
        val to = selection._to

        // 获取块范围，检查是否在列表项内
        val range = from.blockRange(to) { node ->
            node.childCount > 0 && node.firstChild?.type == itemType
        }

        if (range == null) {
            return false
        }

        val startIndex = range.startIndex
        if (startIndex == 0) {
            return false
        }

        val parent = range.parent
        val nodeBefore = parent.child(startIndex - 1)
        if (nodeBefore.type != itemType) {
            return false
        }

        if (dispatch != null) {
            val nestedBefore = nodeBefore.lastChild?.type == parent.type
            val inner = if (nestedBefore) {
                Fragment.from(itemType.create())
            } else {
                Fragment.empty
            }

            val innerFragment = Fragment.from(parent.copy(inner))
            val itemFragment = Fragment.from(itemType.create(null, innerFragment))
            val slice = Slice(itemFragment, if (nestedBefore) 3 else 1, 0)

            val before = range.start
            val after = range.end

            val step = ReplaceAroundStep(
                before - if (nestedBefore) 3 else 1,
                after,
                before,
                after,
                slice,
                1,
                true
            )

            val tr = state.tr.step(step).scrollIntoView()
            dispatch(tr)
        }

        return true
    }
}

fun Command.Companion.sinkListItem(itemType: NodeType) = SinkListItem(itemType)

/**
 * 检查是否可以进行列表项下沉操作
 */
fun EditorState.canSinkListItem(itemType: NodeType): Boolean {
    val state = this
    val selection = state.selection
    val from = selection._from
    val to = selection._to

    val range = from.blockRange(to) { node ->
        node.childCount > 0 && node.firstChild?.type == itemType
    } ?: return false

    val startIndex = range.startIndex
    if (startIndex == 0) return false

    val parent = range.parent
    val nodeBefore = parent.child(startIndex - 1)
    return nodeBefore.type == itemType
}